package com.bifrost.service.impl;

import com.bifrost.common.util.HttpRequestUtils;
import com.bifrost.entity.*;
import com.bifrost.model.brand.BrandModel;
import com.bifrost.model.brand.ProductBrandModel;
import com.bifrost.model.vo.PageVO;
import com.bifrost.repository.MediaRepository;
import com.bifrost.repository.MerchantStoreRepository;
import com.bifrost.repository.ProductBrandRepository;
import com.bifrost.repository.ProductSkuRepository;
import com.bifrost.service.BrandService;
import com.bifrost.util.PinyinUtil;
import com.bifrost.util.ServiceUtils;
import com.bifrost.util.TransformUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.persistence.criteria.*;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author rangf
 * @date 2018/3/28
 */
@Service
public class BrandServiceImpl implements BrandService {


    private static final Logger LOGGER = LoggerFactory.getLogger(BrandServiceImpl.class);
    @Autowired
    ProductBrandRepository productBrandRepository;
    @Autowired
    ProductSkuRepository skuRepository;
    @Autowired
    MediaRepository mediaRepository;
    @Autowired
    MerchantStoreRepository merchantStoreRepository;

    @Override
    public ProductBrand getById(Long brandId) {
        return productBrandRepository.findOne(brandId);
    }

    @Override
    public List<ProductBrand> getBrands(Long categoryId) {
        List<BigInteger> brandIds = null;
        if(categoryId != null){
            brandIds = productBrandRepository.getProductBrandsByCategory(categoryId);
        }else {
            brandIds = productBrandRepository.getProductOfBrands();
        }
        if (CollectionUtils.isNotEmpty(brandIds)) {
            List<ProductBrand> brands = productBrandRepository.getProductBrandsIn(brandIds);
            if (CollectionUtils.isNotEmpty(brands)) {
                return brands.stream().filter(productBrand -> {
                    return !Boolean.TRUE.equals(productBrand.isArchived());
                }).collect(Collectors.toList());
            }
        }
        return null;
    }

    @Override
    public List<ProductBrand> getBrands(List<BigInteger> categoryIds) {
        List<BigInteger> brandIds = null;
        if(CollectionUtils.isNotEmpty(categoryIds)){
            brandIds = productBrandRepository.getProductBrandsByCategorys(categoryIds);
        }else {
            brandIds = productBrandRepository.getProductOfBrands();
        }
        if (CollectionUtils.isNotEmpty(brandIds)) {
            List<ProductBrand> brands = productBrandRepository.getProductBrandsIn(brandIds);
            if (CollectionUtils.isNotEmpty(brands)) {
                return brands.stream().filter(productBrand -> {
                    return !Boolean.TRUE.equals(productBrand.isArchived());
                }).collect(Collectors.toList());
            }
        }
        return null;
    }

    @Override
    public Map<String, List<BrandModel>> getBrandsModel(Long categoryId){
        List<ProductBrand> brandList = getBrands(categoryId);
        if(CollectionUtils.isNotEmpty(brandList)){
            List<BrandModel> modelList = brandList.stream().map(brand-> TransformUtils.transformToBrandModel(brand)).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(modelList)) {
                return modelList.stream().collect(Collectors.groupingBy(BrandModel::getBrandNav));
            }
        }
        return null;
    }

    @Override
    public List<BrandModel> getStoreBrands(MerchantStore store) {
        if(store != null){
            List<BigInteger> brandIds = productBrandRepository.getStoreBrands(store.getMerchantId());
            if (CollectionUtils.isNotEmpty(brandIds)) {
                List<ProductBrand> productBrandList = productBrandRepository.getProductBrandsIn(brandIds);
                if (CollectionUtils.isNotEmpty(productBrandList)) {
                    return productBrandList.stream().filter(brand->!Boolean.TRUE.equals(brand.isArchived())).map(brand->TransformUtils.transformToBrandModel(brand)).collect(Collectors.toList());
                }
            }
        }
        return null;
    }

    @Override
    //@Cacheable(value = "productBrand:page")
    public PageVO findAllPage(Integer page, Integer size, String key, String owner, String origin , String externalIds) {
        Specification specification = new Specification<ProductBrand>() {
            @Override
            public Predicate toPredicate(Root<ProductBrand> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

                ArrayList<Predicate> predicates = new ArrayList<>();
                Predicate isArchived = cb.isFalse(root.get("isArchived"));
                Predicate isArchived1 = cb.isNull(root.get("isArchived"));
                predicates.add(cb.or(isArchived,isArchived1));
                // 筛选externalId
                ServiceUtils.findByExternalIds(predicates,root, cb, externalIds,false);

                if(StringUtils.isNotBlank(key)){
                    predicates.add(cb.like(root.get("brandName"),"%"+key+"%"));
                }
                if(StringUtils.isNotBlank(origin)){
                    predicates.add(cb.like(root.get("brandOrigin"),"%"+origin+"%"));
                }
                if(StringUtils.isNotBlank(owner)){
                    predicates.add(cb.like(root.get("brandOwner"),"%"+owner+"%"));
                }
                Predicate[] p = new Predicate[predicates.size()];
                return cb.and(predicates.toArray(p));
            }
        };

        PageRequest pageRequest = new PageRequest(page - 1, size, Sort.Direction.DESC,"updatedTimestamp");
        Page<ProductBrand> pageBean = productBrandRepository.findAll(specification,pageRequest);
        Assert.notEmpty(pageBean.getContent(),"没有数据");

        ArrayList models = new ArrayList<>();
        pageBean.getContent().stream().forEach( productBrand -> {
            Media brandLogo = productBrand.getBrandLogo();
            ProductBrandModel model = convertToBrandModel(productBrand);
            models.add(model);
        });
        Long totalElements = pageBean.getTotalElements();

        return new PageVO(page, size , totalElements.intValue(),models);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    //@CacheEvict(value = "productBrand:page" , allEntries = true)  //allEntries = true 忽略key 清空value下所有缓存数据
    public void addBrand(User user , ProductBrandModel brandModel) {
        //SaveOrUpdate Brand
        ProductBrand persistenceBrand = null;
        Long brandId = brandModel.getProductBrandId();
        brandModel.setImg(brandModel.getImg().replaceAll(HttpRequestUtils.getUrlAccessPath(),""));
        // 不为空 修改品牌
        if (brandId != null) {
            Assert.notNull(persistenceBrand = productBrandRepository.findOne(brandId),"修改的品牌不存在");
            //前端对象属性copy 到持久化对象 包括null属性乜copy
            BeanUtils.copyProperties(brandModel, persistenceBrand);
        }
        //Persistent object values are not null is must modified , else save.
        if(persistenceBrand!= null){
            persistenceBrand.setUpdatedTimestamp(new Date());
            persistenceBrand.setUpdatedBy(user.getAdminName());
        }else{
            persistenceBrand = new ProductBrand();
            persistenceBrand.setUpdatedBy(user.getAdminName());
            persistenceBrand.setUpdatedTimestamp(new Date());
            BeanUtils.copyProperties(brandModel,persistenceBrand);
        }
        persistenceBrand.setBrandLogo(mediaRepository.findFirstByHash(brandModel.getHash()));
        if(productBrandRepository.save(persistenceBrand)==null){
            LOGGER.warn(String.format("品牌添加/修改失败 %s",persistenceBrand.toString()));
            throw new IllegalArgumentException("品牌保存失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    //@CacheEvict(value = "productBrand:page", allEntries = true)
    public void delete(User user , List<Long> brandIds) {

        //校验数据
        checkDeleteEnable(brandIds);
        productBrandRepository.batchUpdateArchived(user.getAdminName() , brandIds);
        LOGGER.info(String.format("批量删除品牌%s",brandIds.toString()));
    }

    private void checkDeleteEnable(List<Long> brandIds) {
        Assert.notEmpty(brandIds,"品牌id不能为空");
        //org.apache.shiro.util.Assert.noNullElements(brandIds.toArray(),"品牌id不能为空");

        for (Long brandId: brandIds ) {
            //品牌可用
            if(productBrandRepository.countAllByBrand(brandId).compareTo(0L)>1){
                throw new IllegalArgumentException(String.format("品牌: （%s） 还存在未下架商品",productBrandRepository.findOne(brandId).getBrandName()));
            }
        }
    }

    @Override
    public ProductBrandModel findOne(Long brandId) {
        ProductBrand productBrand = productBrandRepository.findOne(brandId);
        Assert.notNull(productBrand,"品牌查询失败");
        return convertToBrandModel(productBrand);
    }

    @Override
    public List findAll() {
        List<ProductBrand> archivedIsFalse = productBrandRepository.findAllByIsArchivedIsNullOrIsArchivedIsFalse();
        Assert.notEmpty(archivedIsFalse,"没有数据");

        List<BrandModel> brandModels = new ArrayList();
        archivedIsFalse.forEach(productBrand -> {
            brandModels.add(convertToModel(productBrand));
        });
        return brandModels;
    }

    /**
     * 通过关键字获取商品品牌
     * @param queryKey
     * @return
     */
    @Override
    public List<BrandModel> getStoreBrands(String queryKey) {
        Specification<ProductSku> query = new Specification<ProductSku>() {
            @Override
            public Predicate toPredicate(Root<ProductSku> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                Join<ProductSku, Product> product = root.join("product", JoinType.INNER);
                predicates.add(cb.or(cb.isFalse(product.get("isOffline")),cb.isNull(product.get("isOffline"))));
                predicates.add(cb.isTrue(root.get("available")));
                predicates.add(cb.isTrue(root.get("isDefault")));
                predicates.add(cb.equal(root.get("auditStatus"),"ON_SALE"));
                if(StringUtils.isNotBlank(queryKey)) {
                    predicates.add(cb.like(root.get("keyword"), "%" + queryKey + "%"));
                }
                Predicate[] p = new Predicate[predicates.size()];
                return cb.and(predicates.toArray(p));
            }
        };
        List<ProductSku> productSkuList = skuRepository.findAll(query);
        if(CollectionUtils.isNotEmpty(productSkuList)){
            List<Long> brandIdList = productSkuList.stream().map(productSku -> productSku.getProductBrandId()).distinct().collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(brandIdList)) {
                List<ProductBrand> productBrandList = productBrandRepository.findAll(brandIdList);
                return productBrandList.stream().filter(brand->!Boolean.TRUE.equals(brand.isArchived())).map(brand->TransformUtils.transformToBrandModel(brand)).collect(Collectors.toList());
            }
        }
        return null;
    }

    public ProductBrandModel convertToBrandModel(ProductBrand brand){
        String brandName = brand.getBrandName();
        if(StringUtils.isNotEmpty(brandName)){
            ProductBrandModel model = new ProductBrandModel();
            /*if(StringUtils.isNotBlank(brand.getImg())){
                if(brand.getImg().startsWith(HttpRequestUtils.getUrlAccessPath())){
                    brand.setImg(brand.getImg().replaceAll(HttpRequestUtils.getUrlAccessPath(),""));
                }
                brand.setImg(HttpRequestUtils.getUrlAccessPath().concat(brand.getImg()));
            }*/
            BeanUtils.copyProperties(brand,model);
            Media media = brand.getBrandLogo();
            model.setImg(media==null?null:HttpRequestUtils.getUrl(media.getUrl()));
            model.setHash(media==null?null:media.getHash());
            model.setBrandNav(PinyinUtil.getPyInitial(StringUtils.left(brandName, 1)).toUpperCase());
            return model;
        }
        return null;
    }

    private BrandModel convertToModel(ProductBrand brand){
        String brandName = brand.getBrandName();
        if(StringUtils.isNotEmpty(brandName)){
            BrandModel model = new BrandModel();
            model.setBrandId(brand.getProductBrandId());
            model.setBrandName(brandName);
            Media media = brand.getBrandLogo();
            model.setBrandImg(media==null?null:HttpRequestUtils.getUrl(media.getUrl()));
            model.setBrandNav(PinyinUtil.getPyInitial(StringUtils.left(brandName, 1)).toUpperCase());
            return model;
        }

        return null;
    }
}
